<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>MyVue</title>
</head>
<body>
    <div id="app">
        <form>
            <input type="text" v-model="number">
            <button type="button" @click = "increment">增加</button>
        </form>
        <h3 v-bind ="number"></h3>
    </div>

    <script>
        MyVue.prototype._init = function(options){
            this.$options = options
            this.$el = document.querySelector(options.el);
            this.$data = options.data;
            this.$methods = options.methods;

            this._binding = {};
            this._obverse(this.$data);
            this._complie(this.$el)
        }

        MyVue.prototype._obverse = function(obj){
            let value;
            for(key in obj){
                if(obj.hasOwnProperty(key)){
                    this._binding[key] = {
                        _directives: []
                    }
                }
                value = obj[key]
                if(typeof value === "object"){
                    this._obverse(value)
                }
                let binding = this._binding[key];
                Object.defineProperty(this.$data, key, {
                    enumerable: true,
                    configurable: true,
                    get: () => {
                        console.log('获取value,${value}')
                        return value
                    },
                    set: newValue => {
                        console.log('修改value.旧值:${value},新值:${newValue}');
                        if(value !== newValue){
                            value = newValue;
                            binding._directives.forEach(item =>{
                                item.update()
                            })
                        }
                    }
                })
            }
            
        }

        MyVue.prototype._complie = function(root){
            let nodes = root.children;
            let _this = this;
            for (var i = 0 ;i < nodes.length ;i++){
                let nodei = nodes[i];
                if(nodei.children.length){
                    _this._complie(nodei)
                }
                if(nodei.hasAttribute('v-click') || nodei.hasAttribute('@click')){
                    nodei.onclick = (function(){
                        let methodName = nodei.getAttribute('v-click') || nodei.getAttribute('@click');
                        return _this.$methods[methodName].bind(_this.$data);
                    })()
                }
                if(nodei.hasAttribute('v-model') && (nodei.tagName == 'INPUT' || nodei.tagName == 'TEXTAREA')){
                    nodei.addEventListener('input', (function(key){
                        let modelName = nodei.getAttribute('v-model');
                        let tagName = nodei.tagName.toLowerCase()
                        _this._binding[modelName]._directives.push(new Watcher('input',nodei,_this,modelName,'value'))
                        return function(){
                            _this.$data[modelName] = nodes[key].value;
                        }
                    })(i))
                }
                if(nodei.hasAttribute('v-bind')){
                    var bindName=nodei.getAttribute('v-bind');
                    _this._binding[bindName]._directives.push(new Watcher('text',nodei,_this,bindName,'innerHTML'))
                }
            }
        }
        
        function Watcher(name, el, vm, exp, attr) {
            this.name = name; //指令名称，例如文本节点，该值设为"text"
            this.el = el; //指令对应的DOM元素
            this.vm = vm; //指令所属myVue实例
            this.exp = exp; //指令对应的值，本例如"number"
            this.attr = attr; //绑定的属性值，本例为"innerHTML"

            this.update()
        }
        Watcher.prototype.update = function () {
            this.el[this.attr] = this.vm.$data[this.exp]
        }

        function MyVue(options) {
            this._init(options, this)
        }

        window.onload = function(){
            let app = new MyVue({
                el: "#app",
                data:{
                    number: 0
                },
                methods:{
                    increment:function(){
                        this.number ++;
                    }
                }
            })
        }
        
    </script>
</body>
</html>